﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HSDc.RingleFlow.Api.Service;
using HSDc.RingleFlow.Api.Kernel;
using HSDc.RingleFlow.Kernel.DBPersit.Dao;
using NUnit.Framework;

namespace HSDc.RingleFlow.Kernel.DBPersit
{
    //[TestFixture]
    public class RuntimeServiceImpl : IRuntimeService
    {
        Api.Kernel.IProcessInstance IRuntimeService.CreateProcessInstance(Api.Kernel.IProcessDefinition definition)
        {
            return CreateInstance(definition, null);
        }

        private ProcessInstance CreateInstance(IProcessDefinition definition, Dictionary<string, object> variables)
        {
            string _id = Guid.NewGuid().ToString();
            ProcessInstance instance = new ProcessInstance(_id, (ProcessDefinition)definition, variables);
            //if (variables != null)
            //    instance.SetVariables(variables);
            RuntimeServiceDao dao = new RuntimeServiceDao();
            dao.NewProcessInstance(instance);
            //MemoryRuntimeEnvironment.instances.Add(_id, instance);
            return instance;
        }

        Api.Kernel.IProcessInstance IRuntimeService.CreateProcessInstance(string definitionId)
        {
            return CreateInstance(RetrieveProcessDefinition(definitionId), null);
        }

        private IProcessDefinition RetrieveProcessDefinition(string definitionId)
        {
            IRepositoryService reposService = new RepositoryServiceImpl();
            return reposService.GetProcessDefinition(definitionId);
        }

        Api.Kernel.IProcessInstance IRuntimeService.CreateProcessInstance(Api.Kernel.IProcessDefinition definition, Dictionary<string, object> variables)
        {
            return CreateInstance(definition, variables);
        }

        Api.Kernel.IProcessInstance IRuntimeService.CreateProcessInstance(string definitionId, Dictionary<string, object> variables)
        {
            return CreateInstance(RetrieveProcessDefinition(definitionId), variables);
        }

        Dictionary<string, object> IRuntimeService.GetVariables(string instanceId)
        {
            RuntimeServiceDao dao = new RuntimeServiceDao();
            List<InstanceVariableDto> variables = dao.RetrieveVariables(instanceId);
            Dictionary<string, object> insVariables = new Dictionary<string, object>();
            foreach (InstanceVariableDto dto in variables)
            {
                insVariables.Add(dto.Variable_Name, dto.Variable_Value);
            }
            return insVariables;
        }

        object IRuntimeService.GetVaraible(string instanceId, string variableName)
        {
            RuntimeServiceDao dao = new RuntimeServiceDao();
            InstanceVariableDto variables = dao.RetrieveVariables(instanceId, variableName);
            return variables.Variable_Value;
        }

        Api.Kernel.IProcessInstance IRuntimeService.GetProcessInstance(string instanceId)
        {
            // Retrieve Process Instance Dto
            RuntimeServiceDao dao = new RuntimeServiceDao();
            ProcessInstanceDto dto = dao.RetrieveProcessInstance(instanceId);
            // Retrieve Variables
            Dictionary<string, object> variables = ((IRuntimeService)this).GetVariables(instanceId);
            ProcessDefinition pd = (ProcessDefinition)
                RetrieveProcessDefinition(dao.RetrieveProcessDefinitionId(dto.ProcessInstance_Belong_Definition));
            List<ActivityInstance> currentTasks = RetrieveCurrentTasks(dao, dto.ProcessInstance_ID, pd);
            List<ActivityInstance> waitTasks = RetrieveWaitTasks(dao, dto.ProcessInstance_ID, pd);
            List<ActivityInstance> completedTasks = RetrieveCompletedTasks(dao, dto.ProcessInstance_ID, pd);
            ProcessInstance pi = new ProcessInstance(dto.ProcessInstance_GUID, pd, currentTasks, waitTasks, completedTasks, variables);
            return pi;
        }

        private List<ActivityInstance> RetrieveCurrentTasks(RuntimeServiceDao dao, int ProcessInstance_ID, ProcessDefinition pd)
        {
            // Retrieve Current Tasks
            return RetrieveTasks(dao, ProcessInstance_ID, pd, TaskState.Open);
        }

        private List<ActivityInstance> RetrieveWaitTasks(RuntimeServiceDao dao, int ProcessInstance_ID, ProcessDefinition pd)
        {
            // Retrieve Current Tasks
            return RetrieveTasks(dao, ProcessInstance_ID, pd, TaskState.Wait);
        }

        private List<ActivityInstance> RetrieveCompletedTasks(RuntimeServiceDao dao, int ProcessInstance_ID, ProcessDefinition pd)
        {
            // Retrieve Complete Tasks
            return RetrieveTasks(dao, ProcessInstance_ID, pd, TaskState.Completed);
        }

        private List<ActivityInstance> RetrieveTasks(RuntimeServiceDao dao, int ProcessInstance_ID, ProcessDefinition pd, TaskState state)
        {
            List<ActivityInstanceDto> acts = dao.RetrieveActivityInstance(ProcessInstance_ID, state);
            List<ActivityInstance> ais = new List<ActivityInstance>();
            foreach (ActivityInstanceDto dto in acts)
            {
                ActivityInstance ai = new ActivityInstance(dto.ActivityInstance_GUID,
                    pd.FindActivity(dao.RetrieveActivityId(dto.ActivityInstance_Belong_Actvity)),
                    dto.ActivityInstance_Assignee, (TaskState)dto.ActivityInstance_Status);
                ais.Add(ai);
            }
            return ais;
        }

        void IRuntimeService.CompleteProcessInstance(Api.Kernel.IProcessInstance instance)
        {
            // Force Complete ProcessInstance
            ((ProcessInstance)instance).ForceComplete();
            //throw new NotImplementedException();
        }

        bool IRuntimeService.IsComplete(string instanceId)
        {
            RuntimeServiceDao dao = new RuntimeServiceDao();
            int hisCount = dao.RetrieveProcessInstanceFromHistory(instanceId);
            return (hisCount == 1);
        }

        [Test]
        public void TestCreateProcessInstanceByDefinitionId()
        {
            string definitionId = "83CEDA43-0E89-4F57-95D7-553FCF721A38";
            Dictionary<string, object> variables = new Dictionary<string, object>();
            variables.Add("emp", "ringle");
            IProcessInstance instance = ((IRuntimeService)this).CreateProcessInstance(definitionId, variables);
        }

        [Test]
        public void TestRetrieveProcessInstance()
        {
            string instanceId = "855e8236-1394-4386-bf0b-bae0e04ea8cb";
            IProcessInstance instance = ((IRuntimeService)this).GetProcessInstance(instanceId);
        }

        [Test]
        public void TestCompleteProcessInstance()
        {
            string instanceId = "855e8236-1394-4386-bf0b-bae0e04ea8cb";
            IProcessInstance instance = ((IRuntimeService)this).GetProcessInstance(instanceId);
            ((IRuntimeService)this).CompleteProcessInstance(instance);
        }
    }
}
